#include "stdio.h"

#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>

namespace sfc::io {

namespace imp {

template <int ID>
struct StdFile {
  static constexpr auto FILENO = 1;

  static auto is_tty() -> bool {
    const auto res = ::isatty(FILENO);
    return res == 1;
  }

  static auto get_column() -> usize {
    struct winsize ws;
    auto res = ::ioctl(1, TIOCGWINSZ, &ws);
    return res == -1 ? 0 : ws.ws_col;
  }

  static auto write(Slice<const u8> s) -> usize {
    auto res = ::write(FILENO, s._ptr, s._len);
    if (res < 0) {
      throw Error::from_os_error(res);
    }
    return usize(res);
  }
};

struct Stdin : StdFile<0> {};

struct Stdout : StdFile<1> {
  [[sfc_inline]] static auto instance() -> LineWriter<Stdout>& {
    static thread_local auto res = LineWriter{Stdout{}};
    return res;
  }
};

struct Stderr : StdFile<2> {
  static constexpr auto FILENO = 2;

  [[sfc_inline]] static auto instance() -> Stderr& {
    static auto res = Stderr{};
    return res;
  }
};

}  // namespace  imp

auto Stdout::is_tty() -> bool {
  return imp::Stdout::is_tty();
}

auto Stdout::get_column() -> usize {
  return imp::Stdout::get_column();
}

auto Stdout::write(Slice<const u8> buf) -> usize {
  return imp::Stdout::instance().write(buf);
}

void Stdout::flush() {
  return imp::Stdout::instance().flush();
}

auto Stderr::write(Slice<const u8> buf) -> usize {
  return imp::Stderr::instance().write(buf);
}

}  // namespace sfc::io
